package com.letoo.sso.common.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @description 敏感词过滤公共类
 * @author <a href="mailto:ly@letoo.com">刘银</a>
 */
public class SensitiveWordUtil {

    private static final Logger LOG = LoggerFactory.getLogger(SensitiveWordUtil.class);

    private static final Map<String, Object> ENDMAP;

    private static final Map<String, Object> MGCMAP;

    // public static final String CHARACTER_REGEX = "[\\u4e00-\\u9fa5\\da-zA-Z0-9]";

    private static final String CHARACTER_REGEX = "[\\u4e00-\\u9fa5]";

    private static final StringBuilder EMPTY_STRINGBUILDER = new StringBuilder(0);

    static {
        ENDMAP = getEndMap();
        MGCMAP = createMgcMap();
    }

    /**
     * @description 每一个敏感词的结束标记
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     */
    protected static final Map<String, Object> getEndMap() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("isEnd", 1);
        return map;
    }

    /**
     * @description 用递归实现DFA算法构建敏感词库
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     * @param map
     *            要创建的敏感词库
     * @param str
     *            敏感词
     * @param index
     *            敏感词中每一个字符的索引
     * @param len
     *            敏感词的长度
     * @return 敏感词库
     */
    @SuppressWarnings({"unchecked","rawtypes"})
    protected static Map<String, Object> createMap(Map map, String str, int index, int len) {
        Map newMap;
        char key = str.charAt(index);
        // 如果不是敏感词最后一个字符
        if (index < len - 1) {
            ++index;
            // 如果词库中没有该敏感词字符，则将字符加入map，并递归
            if (map.get(key) == null) {
                newMap = new HashMap();
                map.put("isEnd", 0);
                map.put(key, createMap(newMap, str, index, len));

                /*
                 * 如果字符已经存在，且已经是结束标记，则不再需要加入后边敏感词了,直接加入结束标记。 如已经有敏感词“我爱你”，后边又有敏感词“我爱你啊”，则只需要“我爱你”，不需要“啊”
                 */
            } else {
                newMap = (Map) map.get(key);

                if ((int) newMap.get("isEnd") == 0) {
                    createMap(newMap, str, index, len);
                }
            }

            /*
             * 如果是最后一个字符，直接加结束标记 如果已经有敏感词“我爱你啊”，后边又有敏感词“我爱你”，则只需要“我爱你”，不需要“啊”
             */
        } else if (index == len - 1) {
            putEndMap(key, map);

        }
        return map;
    }

    /**
     * @description 给敏感词设置结束标记
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     */
    @SuppressWarnings({"unchecked","rawtypes"})
    protected static void putEndMap(Character key, Map map) {
        map.put("isEnd", 0);
        map.put(key, ENDMAP);
    }

    /**
     * @description 加载敏感词库
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     */
    protected static final Map<String, Object> createMgcMap() {
        // 敏感词库文件地址
        InputStreamReader in = new InputStreamReader(SensitiveWordUtil.class.getResourceAsStream("sensitivewordutf8.txt"));
        String sensitiveWord = null;
        int len = 0;
        Map<String, Object> map = new HashMap<>();
        BufferedReader br = null;
        try {
            br = new BufferedReader(in);
            // br = new BufferedReader(new FileReader(new
            // File("F:\\workspace\\miaomiao\\miaomiao-service\\src\\main\\resources\\backup\\sensitivewordutf8.txt")));
            // 读取每一行敏感词，创建词库
            while ((sensitiveWord = br.readLine()) != null) {
                len = sensitiveWord.length();
                if (len > 0) {
                    createMap(map, sensitiveWord, 0, len);
                }
            }
        } catch (IOException e) {
            LOG.error(SensitiveWordUtil.class.getName() + ":敏感词加载失败", e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    /**
     * @description 递归实现DFA算法判断敏感词（未完成间隔字符校验和网址校验）
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     * @param content
     *            要查找的内容
     * @param map
     *            敏感词库Map
     * @param len
     *            内容的长度
     * @param index
     *            从内容字符的index处开始查找
     * @param 敏感词要放入的StringBuilder
     * @return
     */
    @SuppressWarnings("rawtypes")
    protected static StringBuilder filterContent(String content, Map map, int len, int index, StringBuilder sb) {
        // 在内容中得到一个字符
        Character key = content.charAt(index);
        Map newMap = (Map) map.get(key);
        // 如果字符包含在敏感词Map中，将字符加入StringBuilder
        if (newMap != null) {
            sb.append(key);
            // 且已经到敏感词结束标记，表示敏感词匹配，返回有敏感词的StringBuilder
            if ((int) newMap.get("isEnd") == 1) {
                return sb;
                // 如果没有到敏感词结束标记，查找内容的下一个字符，如果下一个字符不是内容的结尾，就递归
            } else {
                index++;
                if (index <= len - 1) {
                    return filterContent(content, newMap, len, index, sb);
                    // 就算前面字符匹配敏感词的一部分，但内容结束了，还没有匹配完整的敏感词，也不算是敏感词，返回空StringBuilder
                } else {
                    return EMPTY_STRINGBUILDER;
                }
            }
            // 如果字符不包含在敏感词中，就返回空StringBuilder
        } else {
            return EMPTY_STRINGBUILDER;
        }
    }

    /**
     * @description 循环实现DFA算法过滤敏感词，包括排除非法字符连接。（有待测试）（未完成网址校验）
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     * @param {@link }
     * @return {@link StringBuilder}
     */
    @SuppressWarnings({"rawtypes"})
    protected static StringBuilder filterConten(String content, Map mgcMap) {

        int len = content.length();
        Map map = mgcMap;
        int incr = 0;
        StringBuilder sb = new StringBuilder();
        if (content != null && content.length() > 0) {

            for (int i = 0; i < len; i++) {
                char key = content.charAt(i);
                // 如果找到敏感词
                if (map.get(key) != null) {
                    map = (Map) map.get(key);
                    sb.append(key);
                    if ((int) map.get("isEnd") == 1) {
                        break;
                    } else {
                        if (i == len - 1)
                            sb.delete(0, sb.length());

                        ++incr;
                    }
                } else {
                    if (!String.valueOf(key).matches(CHARACTER_REGEX)) {
                        if (sb.length() > 0) {
                            sb.append(key);

                        }
                        if (i >= len - 1 && sb.length() > 0) {
                            sb.delete(0, sb.length());
                            break;
                        }
                        ++incr;
                        continue;

                    }
                    sb.delete(0, sb.length());
                    i -= incr;
                    incr = 0;
                    map = mgcMap;
                }
            }

        }
        return sb;

    }

    /**
     * @description 查找敏感词
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     * @param {@link }
     * @return {@link String}
     */
    public static String filterConten(String content) {
        return filterConten(content, MGCMAP).toString();
    }

    /**
     * @description 查找敏感词
     * @author <a href="mailto:ly@letoo.com">刘银</a>
     * @param {@link }
     * @return 包含敏感词的StringBuilder，如果没有，则是空StringBuilder
     */
    protected static StringBuilder findMgc(String content) {
        StringBuilder sb = new StringBuilder();
        // 如果内容不为空且长度大于1，才进行敏感词库匹配
        if (content != null) {
            int len = content.length();
            if (len > 1) {
                for (int i = 0; i < len; i++) {
                    sb = filterContent(content, MGCMAP, len, i, new StringBuilder());
                    if (sb.length() > 0)
                        break;
                }
            }
        }
        return sb;
    }

    public static void main(String[] args) throws Exception {
        StringBuilder filterConten = filterConten("。藏2高清小白。白&色2高清线小白白", MGCMAP);
        System.out.println(filterConten);
        // System.out.println(MGCMAP.get('水'));

    }
}
